package com.siyue.config.realm;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.siyue.entity.Role;
import com.siyue.entity.RoleResource;
import com.siyue.entity.User;
import com.siyue.service.ResourceService;
import com.siyue.service.RoleResourceService;
import com.siyue.service.RoleService;
import com.siyue.service.UserService;
import com.siyue.util.JWTUtil;
import com.siyue.util.JwtToken;
import com.siyue.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component("authorizer")
public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private RoleResourceService roleResourceService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private JWTUtil jwtUtil;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    /**
     * 功能描述:授权管理器
     *
     * @Param principalCollection:
     * @return: org.apache.shiro.authz.AuthorizationInfo
     * @auther: wuhao
     * @date: 2021/3/15 15:43
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user = (User) principalCollection.getPrimaryPrincipal();
        if (null == user) {
            throw new UnknownAccountException("用户不存在");
        }
        Role role = roleService.getById(user.getRoleId());

        if (null != role) {
            authorizationInfo.addRole(role.getCode());
            List<RoleResource> roleResourceList = roleResourceService.list(new LambdaQueryWrapper<RoleResource>().eq(RoleResource::getRoleId, role.getId()));
            for (RoleResource roleResource : roleResourceList) {
                String url = resourceService.getById(roleResource.getResourceId()).getResourceUrl();

                System.out.println(url);
                if (null != url && !"".equals(url)) {
                    authorizationInfo.addStringPermission(url);
                }
            }
        }
        return authorizationInfo;
    }

    /**
     * 功能描述:认证管理器
     *
     * @Param authenticationToken:
     * @return: org.apache.shiro.authc.AuthenticationInfo
     * @auther: wuhao
     * @date: 2021/3/15 15:43
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        if (null == token) {
            throw new AuthenticationException("token为空");
        }
        User user = this.checkUserTokenIsEffect(token);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user,
                token,
                getName()
        );
        return authenticationInfo;
    }

    private User checkUserTokenIsEffect(String token) {
        String username = jwtUtil.getUserName(token);
        if (null == token) {
            throw new AuthenticationException("token非法无效!");
        }
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        if (!jwtTokenRefresh(token, username, user.getPassword())) {
            throw new AuthenticationException("Token失效请重新登录!");
        }
        return user;
    }

    /**
     * 刷新token
     *
     * @param token
     * @param username
     * @param password
     * @return
     */
    private boolean jwtTokenRefresh(String token, String username, String password) {
        String cacheToken = String.valueOf(token);
        if (!"".equals(cacheToken) && null != cacheToken) {
            if (!jwtUtil.verify(cacheToken, username, password)) {
                String newAuthorization = jwtUtil.sign(username, password);
                // 设置超时时间
                redisUtil.setex("PREFIX_USER_TOKEN_" + token, newAuthorization, 30 * 60);
            } else {
                // 设置超时时间
                redisUtil.setex("PREFIX_USER_TOKEN_" + token, cacheToken, 30 * 60);
            }
            return true;
        }
        return false;
    }

}
